//********************************************************************************************
//
// File : icmp.c implement for Internet Control Message Protocol
//
//********************************************************************************************
//
// Copyright (C) 2007
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
// This program is distributed in the hope that it will be useful, but
//
// WITHOUT ANY WARRANTY;
//
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the Free Software Foundation, Inc., 51
// Franklin St, Fifth Floor, Boston, MA 02110, USA
//
// http://www.gnu.de/gpl-ger.html
//
//********************************************************************************************
#include "StrLib.h"
#include "ip.h"
#include "enc28j60.h"
#include "icmp.h"


//********************************************************************************************
//
// The Internet Control Message Protocol (ICMP) is one of the core protocols of the 
// Internet protocol suite. It is chiefly used by networked computers' 
// operating systems to send error messages---indicating, for instance, 
// that a requested service is not available or that a host or router could not be reached.
//
// ICMP differs in purpose from TCP and UDP in that it is usually not used directly 
// by user network applications. One exception is the ping tool, 
// which sends ICMP Echo Request messages (and receives Echo Response messages) 
// to determine whether a host is reachable and how long packets take to get to and from that host.
//
// +------------+-----------+-------------+----------+
// + MAC header + IP header + ICMP header + Data ::: +
// +------------+-----------+-------------+----------+
//
// ICMP header
//
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// +00+01+02+03+04+05+06+07+08+09+10+11+12+13+14+15+16+17+18+19+20+21+22+23+24+25+26+27+28+29+30+31+
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// +         Type          +          Code         +               ICMP header checksum            +
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// +                                            Data :::                                           +
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
//
//********************************************************************************************
U8 cIcmp::icmp_id = 1;
U8 cIcmp::icmp_seq = 1;
//*******************************************************************************************
//
// Function : icmp_send_reply
// Description : Send ARP reply packet from ARP request packet
//
//*******************************************************************************************
void cIcmp::GenerateICMPPacket ( U8 *pBuff )
{
    // In send ICMP request case, generate new ICMP data.
    if ( pBuff[ ICMP_TYPE_P ] == ICMP_TYPE_ECHOREQUEST_V )
    {
        for ( U8 i=0; i<cIP::ICMP_MAX_DATA; i++ )
        {
            pBuff[ ICMP_DATA_P + i ] = 'A' + i;
        }
    }
    // clear icmp checksum
    pBuff[ ICMP_CHECKSUM_H_P ] = 0;
    pBuff[ ICMP_CHECKSUM_L_P ] = 0;

    // calculate new checksum.
    // ICMP checksum calculation begin at ICMP type to ICMP data.
    // Before calculate new checksum the checksum field must be zero.
    U16 ck = cIP::SoftwareChecksum ( &pBuff[ ICMP_TYPE_P ], sizeof(cIP::ICMP_PACKET), 0 );
    pBuff[ ICMP_CHECKSUM_H_P ] = cStrLib::GetHigh16(ck);
    pBuff[ ICMP_CHECKSUM_L_P ] = cStrLib::GetLow16(ck);
}
//*******************************************************************************************
//
// Function : icmp_send_reply
// Description : Send ARP reply packet to destination.
//
//*******************************************************************************************
U8 cIcmp::SendReply ( U8 *pBuff, U8 *pDestMac, U8 *pDestIP )
{

    // check protocol is icmp or not?
    if ( pBuff [ cIP::IP_PROTO_P ] != cIP::IP_PROTO_ICMP_V )
        return 0;

    // check icmp packet type is echo request or not?
    if ( pBuff [ ICMP_TYPE_P ] != ICMP_TYPE_ECHOREQUEST_V )
        return 1;

    // set ethernet header
    cIP::GenerateMacHeader ( pBuff, cIP::MAC_TYPE_IP_VAL, pDestMac );

    // generate ip header and checksum
    cIP::GenerateIpHeader ( pBuff, (((U16)pBuff[cIP::IP_TOTLEN_H_P]<<8)|pBuff[cIP::IP_TOTLEN_L_P]), cIP::IP_PROTO_ICMP_V, pDestIP );

    // generate icmp packet
    pBuff[ ICMP_TYPE_P ] = ICMP_TYPE_ECHOREPLY_V;
    GenerateICMPPacket ( pBuff );

    // send packet to ethernet media
    cEnc28j60::SendPacket ( pBuff, cIP::MAC_HEADER_LEN + cIP::IP_HEADER_LEN + sizeof(cIP::ICMP_PACKET) );
    return 1;
}

